package weeny.pre.face.operation;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.Set;

import javax.swing.JComboBox;
import javax.swing.JTextField;

import prefuse.Visualization;
import prefuse.data.Tuple;
import weeny.pre.event.GroupListener;
import weeny.util.io.ModUtil;
import weeny.util.logs.Debug;

/**
 * Operation which supports:
 * 1) adding filtered items to a certain focus group 
 * 2) removing filtered items from a certain focus group
 * 3) creating a new focus group
 * 4) deleting a certain focus group
 * 
 * @author weeny
 *
 */
public class GroupOperation extends AbstractOperation implements GroupListener{

	protected final static String ADD_ITEM     = "add items to";
	protected final static String REMOVE_ITEM  = "remove items from";
	protected final static String CREATE_GROUP = "create group";
	protected final static String DELETE_GROUP = "delete group";
	/**
	 * If users choose {@value #ADD_ITEM}, {@value #REMOVE_ITEM}, or
	 * {@value #DELETE_GROUP}, we show this combo box component.
	 */
	protected JComboBox focusGroupCombo = new JComboBox();
	/**
	 * If users choose {@value #CREATE_GROUP}, we show this text input field
	 * component.
	 */
	protected JTextField inputField = new JTextField();
	
	/**
	 * Remember the last invoked item
	 */
	protected String activeItem = null;

	/**
	 * Add to the UI components to handle the actual operation. 
	 */
	protected ActionListener listener = new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			Visualization vis = operationBox.getVisualization();
			if (e.getSource() == focusGroupCombo) {
				String grp = focusGroupCombo.getSelectedItem().toString();
				boolean override = ModUtil.isAltDown(e);
				if (activeItem.equals(ADD_ITEM)) {
					Iterator<Tuple> it = operationBox.filteredItems(override);
					Debug.info("Adding items to group: "+grp);
					int cnt = 0;
					while (it.hasNext()){
						Tuple tuple = it.next();
						vis.getFocusGroup(grp).addTuple(tuple);
						cnt++;
					}
					operationBox.updateInfo(cnt+" items are added to "+grp);
				}
				else if (activeItem.equals(REMOVE_ITEM)){
					Iterator<Tuple> it = operationBox.filteredItems(override);
					Debug.info("Removing items from group: "+grp);
					int cnt = 0;
					while (it.hasNext()){
						if(vis.getFocusGroup(grp).removeTuple(it.next())){
							cnt++;
						}
					}
					operationBox.updateInfo(cnt+" items are removed from "+grp);
				}
				else if (activeItem.equals(DELETE_GROUP)) {
					if (vis.getFocusGroup(grp) != null) {
						Debug.info("Deleting group: "+grp);
						vis.removeGroup(grp);
						operationBox.updateInfo("Group deleted: "+grp);
					}
				}
			}
			else if (e.getSource() == inputField){
				String group = inputField.getText();
				if (activeItem.equals(CREATE_GROUP)) {
					if (vis.getFocusGroup(group) == null) {
						Debug.info("Creating group: "+group);
						vis.addFocusGroup(group);
						operationBox.updateInfo("Group created: "+group);
					}
				}
			}
		}
	};

	/**
	 * We set the {@link AbstractOperation#title} for the group of items, and
	 * {@link AbstractOperation#itemList} for the actions we support. We also
	 * add actionListener to the control UI component. And something extra.
	 */
	public GroupOperation(OperationBox operationBox) {
		super(operationBox);
		title = "Group Action";
		itemList.add(ADD_ITEM);
		itemList.add(REMOVE_ITEM);
		itemList.add(CREATE_GROUP);
		itemList.add(DELETE_GROUP);
		focusGroupCombo.addActionListener(listener);
		inputField.addActionListener(listener);
		focusGroupCombo.setPreferredSize(new Dimension(50, 30));
		focusGroupCombo.setMinimumSize(new Dimension(50, 30));
		operationBox.getVisualization().addGroupListener(this);
		//manualy fire once
		groupUpdated(null, null);
	}
	
	/**
	 * Call back function, which is called by {@link OperationBox} when users
	 * choose one operation in the operation combo
	 */
	public void itemInvoked(String item, boolean isAltDown) {
		activeItem = item;
		Debug.info("Item changed to: "+title+" -> "+item);
		operationBox.updateDetail(chooseComponent(item));
	}
	/**
	 * Pick a UI component according to the invoked item
	 */
	protected Component chooseComponent(String item){
		if (item.equals(title))
			return null;
		if (item.equals(CREATE_GROUP)) {
			return inputField;
		}
		else {
			return focusGroupCombo;
		}
	}
	
	//Function of the groupListener, which is added to vis in the constructor
	/**
	 * Because we can {@value #CREATE_GROUP} or {@value #DELETE_GROUP}, the
	 * focus group set may change. So we need to monitor the changes, and change
	 * {@link #focusGroupCombo} accordingly. 
	 */
	public void groupUpdated(String[] added, String[] removed) {
		focusGroupCombo.removeActionListener(listener);
		focusGroupCombo.removeAllItems();
		Set<String> groups = operationBox.getVisualization().getGroups();
		for (String string : groups) {
			if (operationBox.getVisualization().getVisualGroup(string)==null) {
				//if it is null, it means that it is a focus group
				focusGroupCombo.addItem(string);
			}
		}
		focusGroupCombo.addActionListener(listener);
		focusGroupCombo.revalidate();
		focusGroupCombo.repaint();
	}
}